
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>蓝色绿色星球</title>
    <style>
        body {
            overflow: hidden;
            margin: 0;
        }
    </style>
</head>

<body>

    <script type="module">
        // 导入三维模型库
        import * as THREE from "https://cdn.skypack.dev/three@0.136.0";
        // 导入轨道控制库
        import { OrbitControls } from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/controls/OrbitControls";
        // 清除控制台
        console.clear()
        // 创建场景
        let scene = new THREE.Scene()
        // 设置场景背景颜色为深蓝色
        scene.background = new THREE.Color(0x000033)

        // 创建相机
        let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000)
        // 设置相机位置
        camera.position.set(0, 4, 21)

        // 创建渲染器
        let renderer = new THREE.WebGLRenderer()
        // 设置渲染器大小
        renderer.setSize(innerWidth, innerHeight)
        // 把渲染器加入到页面中
        document.body.appendChild(renderer.domElement)
        // 监听窗口大小变化事件
        window.addEventListener("resize", event => {
            camera.aspect = innerWidth / innerHeight
            camera.updateProjectionMatrix()
            renderer.setSize(innerWidth, innerHeight)
        })

        // 创建控制器
        let controls = new OrbitControls(camera, renderer.domElement)
        // 开启阻尼效果
        controls.enableDamping = true
        // 禁用面板
        controls.enablePan
        // 创建全局uniform
        let gu = {
            time: { value: 0 }
        }
        // 创建点的大小数组和移动数组
        let sizes = []
        let shift = []

        // 创建移动函数
        let pushShift = () => {
            shift.push(
                Math.random() * Math.PI,
                Math.random() * Math.PI * 2,
                (Math.random() * 0.9 + 0.1) * Math.PI * 0.1,
                Math.random() * 0.9 + 0.1
            )
        }

        // 创建点的顶点数组（中间的球体）
        let pts = new Array(50000).fill().map(p => {
            sizes.push(Math.random() * 1.5 + 0.5)
            pushShift()
            return new THREE.Vector3().randomDirection().multiplyScalar(Math.random() * 0.5 + 9.5)
        })

        // 添加更多的点（旁边围绕的）
        for (let i = 0; i < 100000; i++) {
            let r = 10, R = 40;
            let rand = Math.pow(Math.random(), 1.5);
            let radius = Math.sqrt(R * R * rand + (1 - rand) * r * r);
            pts.push(new THREE.Vector3().setFromCylindricalCoords(radius, Math.random() * 2 * Math.PI, (Math.random() - 0.5) * 2));
            sizes.push(Math.random() * 1.5 + 0.5);
            pushShift();
        }

        let g = new THREE.BufferGeometry().setFromPoints(pts)
        g.setAttribute("sizes", new THREE.Float32BufferAttribute(sizes, 1))
        g.setAttribute("shift", new THREE.Float32BufferAttribute(shift, 4))

        let m = new THREE.PointsMaterial({
            size: 0.125,
            transparent: true,
            depthTest: false,
            blending: THREE.AdditiveBlending,
            onBeforeCompile: shader => {
                shader.uniforms.time = gu.time
                shader.vertexShader = `
                uniform float time;
                attribute float sizes;
                attribute vec4 shift;
                varying vec3 vColor;
                ${shader.vertexShader}
                `.replace(
                    `gl_PointSize = size;`,
                    `gl_PointSize = size * sizes;`
                ).replace(
                    `#include <color_vertex>`,
                    `#include <color_vertex>
                    float d = length(abs(position)/vec3(40.,10.,40));
                    d=clamp(d,0.,1.);
                    // 修改为星空蓝到霓虹绿
                    vColor = mix(vec3(0.1, 0.1, 0.4), vec3(0.3, 1.0, 0.3), d);`
                ).replace(
                    `#include <begin_vertex>`,
                    `#include <begin_vertex>
                        float t = time;
                        float moveT = mod(shift.x + shift.z * t,PI2);
                        float moveS = mod(shift.y + shift.z * t,PI2);
                        transformed += vec3(cos(moveS) * sin(moveT),cos(moveT),sin(moveS)*sin(moveT)) * shift.w;
                        `
                )

                shader.fragmentShader = `
                    varying vec3 vColor;
                    ${shader.fragmentShader}
                `.replace(
                    `#include <clipping_planes_fragment>`,
                    `#include <clipping_planes_fragment>
                        float d = length(gl_PointCoord.xy - 0.5);
                    `
                ).replace(
                    `vec4 diffuseColor = vec4( diffuse, opacity );`,
                    `vec4 diffuseColor = vec4( vColor, smoothstep(0.5, 0.1, d));`
                );
            }
        })

        let p = new THREE.Points(g, m)
        p.rotation.order = "ZYX"
        p.rotation.z = 0.2
        scene.add(p)

        let clock = new THREE.Clock()
        renderer.setAnimationLoop(() => {
            controls.update()
            let t = clock.getElapsedTime() * 0.5
            gu.time.value = t * Math.PI
            p.rotation.y = t * 0.05
            renderer.render(scene, camera)
        })
    </script>
</body>
</html>
